{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from gs_quant.session import GsSession\n",
    "# external users should substitute their client id and secret; please skip this step if using internal jupyterhub\n",
    "GsSession.use(client_id=None, client_secret=None, scopes=('run_analytics',))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Vol Calendar Functions"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from gs_quant.data import Dataset\n",
    "from gs_quant.timeseries import last_value, forward_vol, percentiles\n",
    "from gs_quant.markets.securities import AssetIdentifier, SecurityMaster\n",
    "import pandas as pd\n",
    "pd.options.display.float_format = '{:,.2f}'.format \n",
    "import warnings\n",
    "from datetime import date\n",
    "warnings.filterwarnings('ignore')\n",
    "import seaborn as sns\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "\n",
    "def vol_calendar_screen(crosses, long_tenor, short_tenor, start_date, end_date, history='2y',boxplot=True, deltaStrike='DN', location='NYC'):\n",
    "    impvol = Dataset('FXIMPLIEDVOL')\n",
    "    data = {}\n",
    "    boxplt = pd.DataFrame()\n",
    "    for bbid in crosses:\n",
    "        asset = SecurityMaster.get_asset(bbid, AssetIdentifier.BLOOMBERG_ID)\n",
    "        long_implied = impvol.get_data(start_date , end_date, bbid=bbid, tenor=long_tenor, deltaStrike=deltaStrike, location=location)[['impliedVolatility']]\n",
    "        short_implied = impvol.get_data(start_date , end_date, bbid=bbid, tenor=short_tenor, deltaStrike=deltaStrike, location=location)[['impliedVolatility']]\n",
    "        spread = (long_implied - short_implied)*100\n",
    "        spread = spread.dropna()\n",
    "       \n",
    "        boxplt[bbid] = spread['impliedVolatility']\n",
    "        data[bbid] = {'Current': last_value(spread['impliedVolatility']),\n",
    "                       f'{history} Min': min(spread['impliedVolatility']),\n",
    "                       f'{history} Max': max(spread['impliedVolatility']),\n",
    "                      '%-ile': last_value(percentiles(spread['impliedVolatility'])),\n",
    "                      }\n",
    "    df = pd.DataFrame(data)\n",
    "    vol_cal_screen = df.transpose()\n",
    "    vol_cal_screen = vol_cal_screen.sort_values(by=['Current'], ascending=False).style.background_gradient(subset=['Current']).format(\"{:.2f}\")\n",
    "    if boxplot:\n",
    "        f, ax = plt.subplots(figsize=(7, 6))\n",
    "        ax = sns.boxplot(data=boxplt, orient=\"h\", palette=\"mako\").set_title('Spread Ranges')\n",
    "    return vol_cal_screen"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#assumes tenors are ordered from shortest to longest\n",
    "def steepest_flattest(crosses, tenors, top=10):\n",
    "    impvol = Dataset('FXIMPLIEDVOL')\n",
    "    vols = pd.DataFrame()\n",
    "    screen = pd.DataFrame(columns=['Cross', 'Tenors', 'Vol Far', 'Vol Near', 'Abs Spread', '%-ile'])\n",
    "    for bbid in crosses:\n",
    "        asset = SecurityMaster.get_asset(bbid, AssetIdentifier.BLOOMBERG_ID)\n",
    "        for tenor in tenors:\n",
    "            imp_vol = impvol.get_data(start , end, bbid=bbid, tenor=tenor, deltaStrike='DN', location='NYC')['impliedVolatility']\n",
    "            vols[bbid + f'_{tenor}'] = imp_vol\n",
    "        for x in tenors[:-1]:\n",
    "            for y in tenors[1:]:\n",
    "                if(x != y):\n",
    "                    vol_far = vols[bbid + f'_{y}']\n",
    "                    vol_near = vols[bbid + f'_{x}']\n",
    "                    spread = vol_far - vol_near\n",
    "                    row = {'Cross' : bbid, 'Tenors': f'{y}' +f'- {x}', 'Vol Far': last_value(vol_far)*100, 'Vol Near': last_value(vol_near)*100, 'Abs Spread' : last_value(spread), \n",
    "                                   '%-ile': last_value(percentiles(spread))}\n",
    "                    screen = screen.append(row, ignore_index=True) \n",
    "    display(screen.sort_values(by=['%-ile'], ascending=False).head(top).style.set_caption(f'{top} Steepest Calendars').background_gradient(subset=['%-ile']))\n",
    "    display(screen.sort_values(by=['%-ile'], ascending=True).head(top).style.set_caption(f'{top} Flattest Calendars').background_gradient(subset=['%-ile']))\n",
    "    return screen"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## FX Volatility Calendar Spread\n",
    "\n",
    "The FX Structuring team uses this analysis to screen for the steepest and flattest spreads between 1y implied volatility - 3m implied volatility.\n",
    "\n",
    "We are pulling [GS FX Implied Volatility](https://marquee.gs.com/s/developer/datasets/FXIMPLIEDVOL) by default. If you are looking for additional history or coverage, please see our premium version [link](https://marquee.gs.com/s/developer/datasets/FXIMPLIEDVOL_PREMIUM)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from gs_quant.datetime import business_day_offset\n",
    "from dateutil.relativedelta import relativedelta\n",
    "# Inputs to modify\n",
    "\n",
    "g10 = ['USDJPY', 'EURUSD', 'AUDUSD', 'GBPUSD', 'USDCAD', 'USDNOK', 'NZDUSD', 'USDSEK', 'USDCHF']\n",
    "\n",
    "end = business_day_offset(date.today(), -1, roll='forward')\n",
    "start = business_day_offset(end - relativedelta(years=2), -1, roll='forward')\n",
    "\n",
    "\n",
    "long_tenor = '1y'\n",
    "short_tenor = '3m'\n",
    "history = '2y'\n",
    "\n",
    "\n",
    "\n",
    "screen = vol_calendar_screen(crosses=g10, long_tenor='1y', short_tenor='3m', start_date=start, end_date=end, boxplot=True)\n",
    "screen"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Steepest  & Flattest Calendars\n",
    "\n",
    "The FX Structuring team uses this analysis to screen for the steepest calendars, both in absolute terms and in percentile terms across multiple tenors. The steepest and flattest calendars are sorted by the percentile of calendar vs. its own history."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "tenors = ['3m', '6m', '1y', '2y']\n",
    "result = steepest_flattest(crosses=g10, tenors=tenors, top=10)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
